﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Windows.Data.Xml.Dom;
using System.Net.Http;
using System.Threading.Tasks;

public class News
{
    private string _NaverHeaderURL = @"http://openapi.naver.com/search?key=7a6113b7791ce0313cb577f437131e3d&";
    private string _GoogleHeaderURL = @"https://news.google.co.kr/news/feeds?";
    private string _DaumHeaderURL = @"http://apis.daum.net/search/web?";

    private static volatile News _instance;

    public static News INSTANCE
    {
        get
        {
            if (_instance == null)
            {
                lock (typeof(News))
                {
                    if (_instance == null) _instance = new News();
                }
            }

            return _instance;
        }
    }

    public News()
    {

    }

    async public Task<NewsList> GetNews(string keyword, SEARCHENGINE site)
    {
        NewsList nl = new NewsList();
        NewsList tempN;
        NewsList tempG;
        NewsList tempD;

        switch (site)
        {
            case SEARCHENGINE.All:
                NewsList temp = await GetAllNews(keyword);                
                foreach (NewsItem item in temp)
                    nl.Add(item);
                break;
            case SEARCHENGINE.Naver:
                tempN = await GetNaverNews(keyword);
                foreach (NewsItem item in tempN)
                    nl.Add(item);
                break;
            case SEARCHENGINE.Google:
                tempG = await GetGoogleNews(keyword);
                foreach (NewsItem item in tempG)
                    nl.Add(item);
                break;
            case SEARCHENGINE.Daum:
                tempD = await GetDaumNews(keyword);
                foreach (NewsItem item in tempD)
                    nl.Add(item);
                break;
            default:
                break;
        }

        return nl;
    }

    private async Task<NewsList> GetAllNews(string keyword)
    {
        NewsList nl = new NewsList();
        
        string strUrl = string.Format("{0}query={1}&target=news&start={2}&display={3}", _NaverHeaderURL, keyword, 1, 5);

        // Naver
        string responseBody = await GetHttpClientResult(strUrl);        

        System.Xml.Linq.XDocument xDoc = System.Xml.Linq.XDocument.Parse(responseBody);

        var newsList = from newsItem in xDoc.Descendants("item")
                       select new NewsItem
                       {
                           ENGINE = SEARCHENGINE.Naver,
                           TITLE = GetValue((string)newsItem.Element("title")),
                           LINK = (string)newsItem.Element("originallink"),
                           DESCRIPTION = (string)newsItem.Element("description"),
                           DATE = (string)newsItem.Element("pubDate")
                       };

        foreach (NewsItem item in newsList.ToArray())
            nl.Add(item);
          

        // Google
        HttpClient hc = new HttpClient();
        strUrl = string.Format("{0}q={1}&output=rss", _GoogleHeaderURL, keyword);

        XmlDocument doc1 = new XmlDocument();
        doc1.LoadXml(await hc.GetStringAsync(strUrl));

        XmlNodeList xnl1 = doc1.SelectSingleNode("rss/channel").ChildNodes;

        int i = 0;

        foreach (IXmlNode item in xnl1)
        {
            if (i >= 5) break;

            if (item.LocalName != null && item.LocalName.Equals("item"))
            {
                NewsItem ni = new NewsItem();
                ni.ENGINE = SEARCHENGINE.Google;
                ni.TITLE = GetNodeValue(item, "title");
                ni.LINK = GetNodeValue(item, "link");
                ni.DESCRIPTION = GetNodeValueGoogle(item, "description");
                ni.DATE = GetNodeValue(item, "pubDate");

                nl.Add(ni);
                i++;
            }
        }

        // Daum
        strUrl = string.Format("{0}q={1}&apikey=DAUM_SEARCH_DEMO_APIKEY&result=50", _DaumHeaderURL, keyword);

        responseBody = await GetHttpClientResult(strUrl);

        i = 0;

        xDoc = System.Xml.Linq.XDocument.Parse(responseBody);

        newsList = from newsItem in xDoc.Descendants("item")
                       select new NewsItem
                       {
                           ENGINE = SEARCHENGINE.Daum,
                           TITLE = GetValue((string)newsItem.Element("title")),
                           LINK = (string)newsItem.Element("link"),
                           DESCRIPTION = (string)newsItem.Element("description"),
                           DATE = (string)newsItem.Element("pubDate")
                       };

        foreach (NewsItem item in newsList.ToArray())
        {
            if (i >= 5) break;

            nl.Add(item);
            i++;
        }

        return nl;
    }

    private string GetValue(string val)
    {
        return val.Replace("&quot;", "\"").Replace("&lt;", "<").Replace("&gt;", ">").Replace("<b>", "").Replace("</b>", "");
    }

    private void GetSocialPicK(ref NewsList nl, string keyword)
    {
        throw new NotImplementedException();
    }

    private async Task<NewsList> GetDaumNews(string keyword)
    {
        NewsList nl = new NewsList();
        
        string strUrl = string.Format("{0}q={1}&apikey=DAUM_SEARCH_DEMO_APIKEY&result=50", _DaumHeaderURL, keyword);

        string responseBody = await GetHttpClientResult(strUrl);

        int i = 0;        

        System.Xml.Linq.XDocument xDoc = System.Xml.Linq.XDocument.Parse(responseBody);

        var newsList = from newsItem in xDoc.Descendants("item")
                    select new NewsItem
                    {
                        ENGINE = SEARCHENGINE.Daum,
                        TITLE = (string)newsItem.Element("title"),
                        LINK = (string)newsItem.Element("link"),
                        DESCRIPTION = (string)newsItem.Element("description"),
                        DATE = (string)newsItem.Element("pubDate")
                    };

        foreach (NewsItem item in newsList.ToArray())
        {
            if (i >= 5) break;

            nl.Add(item);
            i++;
        }

        return nl;
    }

    private async Task<string> GetHttpClientResult(string strUrl)
    {
        HttpClient hc = new HttpClient();
        System.Net.Http.HttpResponseMessage response = await hc.GetAsync(strUrl);
        response.EnsureSuccessStatusCode();
        string responseBody = await response.Content.ReadAsStringAsync();
        return responseBody;
    }

    private async Task<NewsList> GetNaverNews(string keyword)
    {
        return await GetNaverNews(keyword, 1, 5);
    }

    private async Task<NewsList> GetGoogleNews(string keyword)
    {
        NewsList nl = new NewsList();
        HttpClient hc = new HttpClient();
        string strUrl = string.Format("{0}q={1}&output=rss", _GoogleHeaderURL, keyword);

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(await hc.GetStringAsync(strUrl));

        XmlNodeList xnl = doc.SelectSingleNode("rss/channel").ChildNodes;

        int i = 0;

        foreach (IXmlNode item in xnl)
        {
            if (i >= 5) break;

            if (item.LocalName != null && item.LocalName.Equals("item"))
            {
                NewsItem ni = new NewsItem();
                ni.ENGINE = SEARCHENGINE.Google;
                ni.TITLE = GetNodeValue(item, "title");
                ni.LINK = GetNodeValue(item, "link");
                ni.DESCRIPTION = GetNodeValueGoogle(item, "description");
                ni.DATE = GetNodeValue(item, "pubDate");

                nl.Add(ni);
                i++;
            }
        }

        return nl;
    }

    private string GetConvert(string des)
    {
        string[] temp = des.Split(new string[] { "<td" }, StringSplitOptions.RemoveEmptyEntries);

        return temp[0] + "<td" + temp[2].Replace("<br />", "").Replace("padding-top:0.8em;", "");
    }

    private async Task<NewsList> GetNaverNews(string keyword, int start, int display)
    {
        NewsList nl = new NewsList();
        
        string strUrl = string.Format("{0}query={1}&target=news&start={2}&display={3}", _NaverHeaderURL, keyword, start, display);

        //HttpClient hc = new HttpClient();
        //XmlDocument doc = new XmlDocument();
        //doc.LoadXml(await hc.GetStringAsync(strUrl));

        //XmlNodeList xnl = doc.SelectSingleNode("rss/channel").ChildNodes;

        ////foreach (IXmlNode item in xnl.OfType<IXmlNode>().Where(c => c.LocalName.Equals("item") && !string.IsNullOrEmpty(GetNodeValue(c, "originallink"))))
        ////{
        ////    NewsItem ni = new NewsItem();
        ////    ni.ENGINE = SEARCHENGINE.Naver;
        ////    ni.TITLE = GetNodeValue(item, "title");
        ////    ni.LINK = GetNodeValue(item, "originallink");
        ////    ni.DESCRIPTION = GetNodeValue(item, "description");
        ////    ni.DATE = GetNodeValue(item, "pubDate");

        ////    nl.Add(ni);
        ////}

        //foreach (IXmlNode item in xnl)
        //{
        //    if (item.LocalName != null && item.LocalName.Equals("item"))
        //    {
        //        if (!string.IsNullOrEmpty(GetNodeValue(item, "originallink")))
        //        {
        //            NewsItem ni = new NewsItem();
        //            ni.ENGINE = SEARCHENGINE.Naver;
        //            ni.TITLE = GetNodeValue(item, "title");
        //            ni.LINK = GetNodeValue(item, "originallink");
        //            ni.DESCRIPTION = GetNodeValue(item, "description");
        //            ni.DATE = GetNodeValue(item, "pubDate");

        //            nl.Add(ni); 
        //        }
        //    }
        //}

        string responseBody = await GetHttpClientResult(strUrl);

        int i = 0;

        System.Xml.Linq.XDocument xDoc = System.Xml.Linq.XDocument.Parse(responseBody);

        var newsList = from newsItem in xDoc.Descendants("item")
                    select new NewsItem
                    {
                        ENGINE = SEARCHENGINE.Naver,
                        TITLE = (string)newsItem.Element("title"),
                        LINK = (string)newsItem.Element("originallink"),
                        DESCRIPTION = (string)newsItem.Element("description"),
                        DATE = (string)newsItem.Element("pubDate")
                    };

        foreach (NewsItem item in newsList.ToArray())
        {
            if (i >= 5) break;

            nl.Add(item);
            i++;
        }

        return nl;
    }

    private string GetNodeValue(IXmlNode parent, string name)
    {
        try
        {
            return WebUtility.UrlDecode(parent.SelectSingleNode(name).InnerText).Replace("<b>", "").Replace("</b>", "").Replace("&quot;", "\"");
        }
        catch
        {
            return null;
        }
    }

    private string GetNodeValueGoogle(IXmlNode parent, string name)
    {
        try
        {
            return WebUtility.UrlDecode(GetConvert(parent.SelectSingleNode(name).InnerText)).Replace("<b>", "").Replace("</b>", "");
        }
        catch
        {
            return null;
        }
    }
}

public class NewsItem : Hoons_Player.Common.BindableBase
{
    internal SEARCHENGINE _engin;
    public SEARCHENGINE ENGINE
    {
        get { return this._engin; }
        set { this.SetProperty(ref this._engin, value); }
    }

    internal string _title;
    public string TITLE
    {
        get { return this._title; }
        set { this.SetProperty(ref this._title, value); }
    }

    internal string _link;
    public string LINK
    {
        get { return this._link; }
        set { this.SetProperty(ref this._link, value); }
    }

    internal string _description;
    public string DESCRIPTION
    {
        get { return this._description; }
        set { this.SetProperty(ref this._description, value); }
    }

    internal string _date;
    public string DATE
    {
        get { return this._date; }
        set { this.SetProperty(ref this._date, value); }
    }
}

public class NewsList : List<NewsItem>
{

}

public enum SEARCHENGINE : int
{
    All = 0,
    Naver,
    Google,
    Daum
}
